package com.rp.common.config.shiro;

import com.rp.common.utils.IPUtils;
import com.rp.common.config.redis.RedisUtil;
import com.rp.common.utils.SpringContextUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.apache.shiro.web.util.WebUtils;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.concurrent.TimeUnit;

/**
 * @author:
 * @date: 2018/11/27
 * @description: 自定义 LogoutFilter
 */
@Slf4j
public class UrlFilter extends AccessControlFilter {

    //单位时间内最大访问数
    private static final Integer MAX_COUNT = 10000;
    //单位时间
    //一秒钟内访问15次
    private static final Long UNIT_TIME = 10 * 1000L;
    //限制时长
    private static final Long REJECT_TIME = 10 * 60 * 1000L;



    @Override
    protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) throws Exception {
        return false;
    }

    @Override
    protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {

        RedisUtil redisUtil = (RedisUtil) SpringContextUtils.getBean(RedisUtil.class);

        HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;

        String ip = IPUtils.getIpAddr(httpRequest);
        boolean boo = true;
        //过滤黑名单
        if (redisUtil.hasKey("filter:ip:black:" + ip)) {
            //log.error("ip访问过于频繁，已被限制=>" + ip + " 倒计时" + redisUtil.getExpire("filter:ip:black:" + ip));
            boo = false;
        }
        //判断ip是否首次访问
        if (redisUtil.hHasKey("filter:ip:normal", "count:" + ip)) {
            //判断最大访问次数
            Integer maxCount = Integer.valueOf(redisUtil.hget("filter:ip:normal", "count:" + ip).toString());
            //log.info("ip：" + ip + " 访问" + maxCount + "次");
            if (maxCount > MAX_COUNT) {
                Long maxTime = Long.valueOf(redisUtil.hget("filter:ip:normal", "time:" + ip).toString());
                if (System.currentTimeMillis() - maxTime < UNIT_TIME) {
                    log.error("ip访问过于频繁，已被限制=>" + ip + " 倒计时" + REJECT_TIME);
                    redisUtil.setEx("filter:ip:black:" + ip, "1", REJECT_TIME, TimeUnit.MILLISECONDS);
                    String str[] = {"count:" + ip, "time:" + ip};
                    redisUtil.hdel("filter:ip:normal", str);
                    boo = false;
                }
                initVisitsIP(ip);
            }
        } else {
            initVisitsIP(ip);
        }
        redisUtil.hincr("filter:ip:normal", "count:" + ip, 1);
        if (!boo) {
            WebUtils.issueRedirect(servletRequest, servletResponse, "/redirect/accessRestricted?time=" + redisUtil.getExpire("filter:ip:black:" + ip));
            return false;
        }
        return true;


    }

    /**
     * 初始化访问ip
     *
     * @param ip
     */
    private void initVisitsIP(String ip) {
        RedisUtil redisUtil = (RedisUtil) SpringContextUtils.getBean(RedisUtil.class);
        redisUtil.hset("filter:ip:normal", "count:" + ip, 0);
        redisUtil.hset("filter:ip:normal", "time:" + ip, String.valueOf(System.currentTimeMillis()));
    }
}

